package com.budwk.app.base.filedetection;

import lombok.extern.slf4j.Slf4j;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;

import java.io.*;

/**
 * @title: FileDetection
 * @Author Tan
 * @Date: 2023/11/2 14:47
 * @Version 1.0
 */
@Slf4j
@IocBean
public class FileDetection {

    @Inject
    private PropertiesProxy propertiesProxy;


    private static final String CLAMAV_PATH = "cusconfig.report.clamavPath";


    /**
     * 上传文件安全检测
     *
     */
    public void uploadFileDetection(File file) throws IOException {
        String absolutePath=file.getAbsolutePath();

        //文件头检验
        getFileType(absolutePath);

        //文件大小检测
        //checkFile(file,200.0);

        //使用安全扫描工具对上传的文件进行检测（扫描工具：ClamAV）
        clamAVDetection(absolutePath);


    }



    //文件头检测

    /**
     * 获取文件头
     *
     * @param filePath 文件路径
     * @return 16 进制的文件投信息
     * @throws IOException
     */
    private static String getFileHeader(String filePath) throws IOException {
        byte[] b = new byte[28];
        InputStream inputStream = new FileInputStream(filePath);
        inputStream.read(b, 0, 28);
        inputStream.close();
        return bytes2hex(b);
    }

    /**
     * 将字节数组转换成16进制字符串
     */
    private static String bytes2hex(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (byte b : src) {
            int v = b & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 根据文件路径获取文件类型
     *
     * @param filePath 文件路径
     * @return 文件类型
     * @throws IOException
     */
    public static FileType getFileType(String filePath) throws IOException {
        String fileHead = getFileHeader(filePath);
        if (null == fileHead || fileHead.length() == 0) {
            return null;
        }
        fileHead = fileHead.toUpperCase();
        FileType[] fileTypes = FileType.values();
        for (FileType type : fileTypes) {
            if (fileHead.startsWith(type.getValue())) {
                return type;
            }
        }
        return null;
    }



    //文件大小校验

    public static void checkFile(File file, Double fileMaxSize){
// 检查文件是否存在
        if (file.exists()) {
            // 获取文件大小（以字节为单位）
            long fileSize = file.length();

            // 将文件大小从字节转换为其他单位，如KB、MB或GB
            //double fileSizeKB = fileSize / 1024.0; // 文件大小（KB）
            double fileSizeMB = fileSize / 1024.0 / 1024.0; // 文件大小（MB)
            //double fileSizeGB = fileSizeMB / 1024.0; // 文件大小（GB)
            if (fileSize <= 0) {
                throw new RuntimeException("文件内容为空");
            }
            if (fileSizeMB > fileMaxSize){
                throw new RuntimeException("文件上传内容大小超出限制");
            }
        } else {
            System.out.println("文件不存在或无法访问。");
        }



    }






    //使用安全扫描工具对上传的文件进行检测（扫描工具：ClamAV）
    public void  clamAVDetection(String filePath){
        try {
            String winClamavPath=propertiesProxy.get(CLAMAV_PATH);
            // 调用ClamAV命令行工具进行文件扫描
            ProcessBuilder processBuilder = new ProcessBuilder(winClamavPath, filePath);
            Process process = processBuilder.start();

            // 读取ClamAV的输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            // 等待扫描进程完成
            int exitCode = process.waitFor();

            if (exitCode == 0) {
                System.out.println("文件是安全的。");
            } else {
                System.out.println("文件可能包含恶意软件或病毒。");
                throw new RuntimeException("文件可能包含恶意软件或病毒");
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }




    }




}
